package org.devocean.groupbuying.web.backend;

import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.devocean.groupbuying.domain.Article;
import org.devocean.groupbuying.domain.CategoriesLocalization;
import org.devocean.groupbuying.domain.Deal;
import org.devocean.groupbuying.domain.Discount;
import org.devocean.groupbuying.domain.Formula;
import org.devocean.groupbuying.domain.Media;
import org.devocean.groupbuying.domain.PurchaseItem;
import org.devocean.groupbuying.service.DealService;
import org.devocean.groupbuying.service.UserService;
import org.devocean.groupbuying.utils.RenderMapUtils;
import org.devocean.groupbuying.utils.UriUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value = { "/gb-cpanel/deals" })
public class DealsController {
	
	@Autowired
	private DealService dealService;
	
	@Autowired
	private UserService userService;
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public Map<String, ? extends Object> list(
			@RequestParam(value = "start", required = false) Integer start,
			@RequestParam(value = "limit", required = false) Integer size) {
		try {			
			int sizeNo = size == null ? 10 : size.intValue();
			List<Deal> deals = dealService.getDealsEntries(start, sizeNo);
			List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
			
			for (Deal deal : deals) {
				Set<Article> articles = deal.getArticlesLocalization().getArticles();
				Iterator<Article> articleIterator = articles.iterator();
				
				while (articleIterator.hasNext()) {
					Article article = articleIterator.next();
					Map<String, Object> data = new ConcurrentHashMap<String, Object>();
					data.put("dealID", deal.getDealID());
					data.put("productID", deal.getProduct().getProductID());
					data.put("articleID", article.getArticleID());
					data.put("title", article.getTitle());
					data.put("al_id", deal.getArticlesLocalization().getArticlesLocalizationID());
					data.put("lang", article.getLang());
					result.add(data);
				}
			}
			long total = dealService.countDeals();
			return RenderMapUtils.getMap(result, total);
		} catch (Exception e) {
			e.printStackTrace();
			return RenderMapUtils.getModelMapError("Error retrieving Deals from database.");
		}
	}
	
	@RequestMapping(value = "/", method = RequestMethod.POST)
	public @ResponseBody Map<String, ? extends Object> addOrUpdate(@RequestBody Deal deal, Principal principal) {
		try {			
			deal.getArticlesLocalization().getArticles().iterator().next()
			.setOwner(userService.getUserById(Integer.valueOf(principal.getName())));
			deal = dealService.addOrUpdateDeal(deal);
			
			Map<String, Object> data = new ConcurrentHashMap<String, Object>();
			Article article = deal.getArticlesLocalization().getArticles().iterator().next();
			data.put("articleID", article.getArticleID());
			data.put("title", article.getTitle());
			data.put("lang", article.getLang());
			data.put("articlesLocalizationID", deal.getArticlesLocalization().getArticlesLocalizationID());
			data.put("dealID", deal.getDealID());
			data.put("productID", deal.getProduct().getProductID());
			return RenderMapUtils.getMap(data);
		} catch (Exception e) {
			e.printStackTrace();
			return RenderMapUtils.getModelMapError("Error saving Deal to database.");
		}
	}
	
	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public Map<String, ? extends Object> edit(@PathVariable("id") Integer id) {
		try {
			Deal deal = dealService.getDealByArticleID(id);
			return RenderMapUtils.getMap(this.renderDeal(deal));								
		} catch (Exception e) {
			e.printStackTrace();
			return RenderMapUtils.getModelMapError("Error retrieving Deal from database.");
		}
	}
	
	@RequestMapping(value = "/localize", method = RequestMethod.GET)
	public Map<String, ? extends Object> localize(Integer LocalizationKey, String LocalizationRequest) {
		try {
			Deal deal = dealService.getDealByLang(LocalizationKey,LocalizationRequest);
			return RenderMapUtils.getMap(this.renderDeal(deal));
		} catch (Exception e) {
			e.printStackTrace();
			return RenderMapUtils.getModelMapError("Error retrieving Deal from database.");
		}
	}
	
	private Map<String, Object> renderDeal(Deal deal){
		Integer[] cl_ids = new Integer[deal.getArticlesLocalization().getCategoriesLocalizations().size()];
		SimpleDateFormat simpleFormat = new SimpleDateFormat("MM/dd/yyyy");
		Map<String, Object> data = new ConcurrentHashMap<String, Object>();
		if(deal.getArticlesLocalization().getArticles()!=null){
			Article article = deal.getArticlesLocalization().getArticles().iterator().next();
			data.put("title", article.getTitle());
			data.put("shorte", article.getShorte());
			data.put("body",  article.getBody());
			data.put("articleID", article.getArticleID());
			data.put("lang", article.getLang());
			data.put("fineprint",article.getAdditionalContents().get("fineprint"));
		}
						
		data.put("dealID", deal.getDealID());
		data.put("expireDate", simpleFormat.format(deal.getExpireDate()));
		data.put("startDate", simpleFormat.format(deal.getStartDate()));
		data.put("tippingPoint", deal.getTippingPoint());
		data.put("purchaseNumber", deal.getPurchaseNumber());
		data.put("maxPurchase", deal.getMaxPurchase());
		data.put("type", deal.getType());
		data.put("status",  deal.getStatus());
		data.put("productID", deal.getProduct().getProductID());		
		data.put("articlesLocalizationID", deal.getArticlesLocalization().getArticlesLocalizationID());
		
		int i = 0;
		Iterator<CategoriesLocalization> iteratorCategories = deal.getArticlesLocalization().getCategoriesLocalizations().iterator();
		while (iteratorCategories.hasNext()) {
			cl_ids[i++] = iteratorCategories.next().getCategoriesLocalizationID();			
		}
		
		List<Map<String, Object>> mediaList = new ArrayList<Map<String, Object>>();		
		for (Media m :	deal.getArticlesLocalization().getMediaLocalizations()) {
			Map<String, Object> dataMedia = new ConcurrentHashMap<String, Object>();
			dataMedia.put("mediaID", m.getMediaID());
			dataMedia.put("title", m.getTitle());
			dataMedia.put("media_file_path", m.getMediaFilePath());
			mediaList.add(dataMedia);

		}
		data.put("articlesMedia", mediaList);
		data.put("_categoriesProxy", cl_ids);
		return data;
	}
	
	@RequestMapping(value = "/{dealID}/product/{productID}", method = RequestMethod.GET)
	public Map<String, ? extends Object>  listFormulas(@PathVariable("dealID") Integer dealID, @PathVariable("productID") Integer productID) {
		try {		
			List<Formula> formulas =  dealService.getFormulasByProductId(productID);				
			List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
			for(Formula formula : formulas){
				Map<String, Object> data = new ConcurrentHashMap<String, Object>();
				data.put("planID", formula.getPlan().getPlanID());				
				data.put("formulaID",formula.getFormulaID());
				data.put("frequency",formula.getFrequency());
				data.put("factor",formula.getFactor());
				data.put("currency",formula.getCurrency());
				data.put("choice",formula.getChoice());
				data.put("price",formula.getPrice());
				data.put("maxPurchasePerClient",10000);
				data.put("selected", false);
				data.put("title",formula.getPlan().getArticlesLocalization().getArticles().iterator().next().getTitle());
				Discount discount = dealService.getDiscountByDealID(dealID, formula.getFormulaID());
				if(discount != null)
				{
					data.put("discountID",discount.getDiscountID());
					data.put("merchentDiscount",discount.getMerchentDiscount());
					data.put("discountPrice",discount.getDiscountPrice());
					data.put("discountValue",discount.getDiscountValue());				
					data.put("commission",discount.getCommission());
					data.put("maxPurchasePerClient",discount.getMaxPurchasePerClient());
					data.put("selected", true);
				}
				data.put("strategy", 1);
				
				results.add(data);
			}
		return RenderMapUtils.getMap(results);
		} catch (Exception e) {
			return RenderMapUtils.getModelMapError("Error retrieving Formulas from database.");
		}
	}
	
	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
	public void delete(@PathVariable("id") Integer id) {
		try {
			dealService.removeDeal(id);
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}
	
	@RequestMapping(value = "/{dealID}/purchases", method = RequestMethod.GET)
	public Map<String, ? extends Object> getPurchases(@PathVariable("dealID") Integer dealID) {
		try {
			
			List<PurchaseItem> purchases = dealService.getPurchaseItemsByDealID(dealID);			
			List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();			
			for (PurchaseItem purchaseItem : purchases) {
				Map<String, Object> data = new ConcurrentHashMap<String, Object>();
				data.put("id", purchaseItem.getPurchaseItemID());
				data.put("unitPrice", purchaseItem.getUnitPrice());
				data.put("amount", purchaseItem.getAmount());
				data.put("quantity", purchaseItem.getQuantity());
				data.put("statusDate", purchaseItem.getStatusDate().toString());
				data.put("status", purchaseItem.getStatus());
				result.add(data);
			}
			return RenderMapUtils.getMap(result, result.size());
		} catch (Exception e) {
			return RenderMapUtils
					.getModelMapError("Error retrieving Purchase Items from database.");
		}
	}
	
	@RequestMapping(value = "/search", method = RequestMethod.GET)
	public Map<String,Object> search(String searchText,
									@RequestParam(value = "start", required = false) Integer start,
									  @RequestParam(value = "limit", required = false) Integer limit) {
		try {
			 
			return dealService.search(searchText, new ConcurrentHashMap<String, Object>(3));
			 			
		} catch (Exception e) {
			e.printStackTrace();
			return RenderMapUtils.getModelMapError("No data found!");

		}
	
	}

}
